﻿using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace BrokenDelusionMod.Install
{
    class Inject
    {
        struct moduleDEFMD_class
        {
            public ModuleDefMD module;
            public string loadPath;
            public string backupPath;
        }

        moduleDEFMD_class moduleDEFMD_Class;

        bool isOk = false;
        public bool IsOk
        {
            get
            {
                return isOk;
            }
        }
        
        public Inject(string path)
        {
            if (!File.Exists(path))
            {
                Program.Log("未发现这个路径：" + path);
                return;
            }
            moduleDEFMD_Class = new moduleDEFMD_class { module = ModuleDefMD.Load(File.ReadAllBytes(path)), loadPath = path, backupPath = path + ".bak"};
            isOk = true;
        }

        public bool Install()
        {
            ModuleDefMD moduleDefMD = moduleDEFMD_Class.module;
            foreach (TypeDef type in moduleDefMD.Types)
            {
                if (type.Name == "Mod")
                {
                    Program.Log("安装失败：已安装，若要重新安装请先卸载mod");
                    return false;
                }
            }
            File.Copy(moduleDEFMD_Class.loadPath, moduleDEFMD_Class.backupPath,true);
            
            Type modTypeRef = typeof(Manager.Mod);
            ModuleDefMD modModule = ModuleDefMD.Load(modTypeRef.Module);
            List<TypeDef> typeList = new List<TypeDef>();
            foreach (TypeDef type in modModule.Types)
            {
                typeList.Add(type);
            }
            foreach (TypeDef type in typeList)
            {
                modModule.Types.Remove(type);
                moduleDefMD.Types.Add(type);
            }
            return true;
        }
        public bool Uninstall()
        {
            try
            {
                File.Copy(moduleDEFMD_Class.loadPath + ".bak", moduleDEFMD_Class.loadPath, true);
                Program.Log("卸载成功");
                return true;
            }
            catch
            {
                Program.Log("卸载失败，请先确定是否存在备份文件或关闭游戏，若依然不行可以直接验证游戏完整性");
                return false;
            }
        }

        public void InjectFunHead(string targetType, string targetMethod, string selfType, string selfMethod)
        {
            ModuleDefMD modModule = moduleDEFMD_Class.module;
            TypeDef modType = modModule.Types.First(x => x.Name == selfType);
            Program.Log("注入" + targetType + "." + targetMethod);
            MethodDef startMethod = modModule.Types.First(x => x.Name == targetType).Methods.First(x => x.Name == targetMethod);
            Instruction instr = OpCodes.Call.ToInstruction(modType.Methods.First(x => x.Name == selfMethod));
            startMethod.Body.Instructions.Insert(0, instr);
        }
        public void InjectFunTail(string targetType, string targetMethod, string selfType, string selfMethod)
        {
            ModuleDefMD modModule = moduleDEFMD_Class.module;
            TypeDef modType = modModule.Types.First(x => x.Name == selfType);
            Program.Log("注入" + targetType + "." + targetMethod);
            MethodDef startMethod = modModule.Types.First(x => x.Name == targetType).Methods.First(x => x.Name == targetMethod);
            Instruction instr = OpCodes.Call.ToInstruction(modType.Methods.First(x => x.Name == selfMethod));
            startMethod.Body.Instructions.Insert(startMethod.Body.Instructions.Count - 2, instr);
        }
        public bool InstallEnd()
        {
            try
            {
                moduleDEFMD_Class.module.Write(moduleDEFMD_Class.loadPath);
                Program.Log("成功安装");
                return true;
            }
            catch
            {
                Program.Log("安装失败，请先确认是否关闭游戏");
                return false;
            }
        }
    }
}
